home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Resources / Chat & Communication / Digsby build 37 / digsby_setup.exe / lib / common / favicons.pyo (.txt) < prev    next >
Python Compiled Bytecode  |  2008-10-13  |  7KB  |  241 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.5)
  3.  
  4. from __future__ import with_statement
  5. from threading import RLock, currentThread
  6. from time import time
  7. import wx
  8. from cStringIO import StringIO
  9. from path import path
  10. from util import WeakDelegate
  11. from util.cacheable import get_cache_root
  12. from util.lrucache import lru_cache, LRU
  13. from common import netcall
  14. import common.asynchttp as asynchttp
  15. from logging import getLogger
  16. log = getLogger('favicons')
  17. __all__ = ('favicon',)
  18. FETCHING = object()
  19. EMPTY = object()
  20. FAVICON_EXPIRE_SECS = 2592000
  21. FAVICON_EXPIRE_ERROR_SECS = 86400
  22. FAVICON_CACHE_DIR = 'favicons'
  23. ICON_EXT = '.ico'
  24. LINK_EXT = '.redirect'
  25. MAX_SUBDOMAIN_CHECK = 5
  26. _favicons_lru = { }
  27. _domain_lru = { }
  28. manual_redirects = {
  29.     'gmail.com': 'mail.google.com',
  30.     'facebookmail.com': 'www.facebook.com',
  31.     'papajohns-specials.com': 'papajohns.com',
  32.     'papajohnsonline.com': 'papajohns.com' }
  33.  
  34. def favicon(domain):
  35.     cached = get_cached(domain)
  36.     if cached in (FETCHING, EMPTY):
  37.         return None
  38.     elif cached is not None:
  39.         return cached
  40.     else:
  41.         fetch_favicon(domain)
  42.  
  43. on_icon = WeakDelegate()
  44.  
  45. def cache_path():
  46.     p = get_cache_root() / FAVICON_CACHE_DIR
  47.     if not p.isdir():
  48.         p.makedirs()
  49.     
  50.     return p
  51.  
  52.  
  53. def clear_cache():
  54.     cache_path().rmtree()
  55.  
  56.  
  57. def get_icon_domain(domain):
  58.     domain = manual_redirects.get(domain, domain)
  59.     if domain in _domain_lru:
  60.         return _domain_lru[domain]
  61.     
  62.     root = cache_path()
  63.     p = root / (domain + LINK_EXT)
  64.     if p.isfile():
  65.         result = p.bytes()
  66.     else:
  67.         result = domain
  68.     _domain_lru[domain] = result
  69.     return result
  70.  
  71.  
  72. def get_cached(domain, done_fetching = False):
  73.     domain = get_icon_domain(domain)
  74.     if domain in _favicons_lru:
  75.         return _favicons_lru[domain]
  76.     
  77.     if not done_fetching and is_fetching(domain):
  78.         return FETCHING
  79.     
  80.     cache_file = cache_path() / domain + ICON_EXT
  81.     if not cache_file.isfile():
  82.         return None
  83.     
  84.     age = time() - cache_file.mtime
  85.     if not done_fetching:
  86.         if age > FAVICON_EXPIRE_SECS or age < 0:
  87.             log.info('expiring favicon for %s' % domain)
  88.             cache_file.remove()
  89.             return None
  90.         
  91.     
  92.     if cache_file.size == 0:
  93.         if age > FAVICON_EXPIRE_ERROR_SECS:
  94.             log.info('expiring empty favicon cache file for %s' % domain)
  95.             cache_file.remove()
  96.             return None
  97.         
  98.         log.debug('%s has an empty cache file', domain)
  99.         _favicons_lru[domain] = EMPTY
  100.         return EMPTY
  101.     
  102.     
  103.     try:
  104.         import wx as wx
  105.         log.debug('loading favicon cache file for %s', domain)
  106.         bitmap = wx.Bitmap(cache_file)
  107.         if not bitmap.IsOk():
  108.             raise Exception('bitmap.IsOk() != True')
  109.     except Exception:
  110.         e = None
  111.         log.warning('Error loading image file: %s' % e)
  112.         cache_file.remove()
  113.  
  114.     _favicons_lru[domain] = bitmap
  115.     on_icon(domain)
  116.     return bitmap
  117.  
  118.  
  119. def cache_icon(domain, linked_domains, data):
  120.     cp = cache_path()
  121.     icon_file = cp / domain + ICON_EXT
  122.     if icon_file.isfile():
  123.         log.warning('caching file to %s but it already exists', icon_file)
  124.     
  125.     icon_file.write_bytes(data)
  126.     for d in linked_domains:
  127.         (cp / d + LINK_EXT).write_bytes(domain)
  128.     
  129.     _domain_lru.clear()
  130.     wx.CallAfter(get_cached, domain, done_fetching = True)
  131.     log.debug('cached %d bytes of data for %r (linked: %s)', len(data), domain, ', '.join(linked_domains))
  132.  
  133.  
  134. def cache_noicon(domain, linked_domains):
  135.     return cache_icon(domain, linked_domains, '')
  136.  
  137.  
  138. def fetch_favicon(domain, linked_domains = None):
  139.     real_domain = get_icon_domain(domain)
  140.     if linked_domains is None:
  141.         linked_domains = []
  142.     
  143.     if real_domain != domain:
  144.         linked_domains.append(domain)
  145.     
  146.     domain = real_domain
  147.     wwwdomain = 'www.' + domain
  148.     if not domain.startswith('www') or wwwdomain in linked_domains:
  149.         linked_domains.append(domain)
  150.         domain = wwwdomain
  151.     
  152.     url = 'http://' + domain + '/favicon.ico'
  153.     
  154.     def on_success(req, resp):
  155.         data = resp.read()
  156.         log.info('httpopen(%s): received %d bytes of data', url, len(data))
  157.         log.info('%r', resp)
  158.         cache_icon(domain, linked_domains, data)
  159.         unset_fetching([
  160.             domain])
  161.  
  162.     
  163.     def on_error(req = (None, None, None), resp = (None, None)):
  164.         log.error('on_error for domain=%r, linked_domains=%r', domain, linked_domains)
  165.         if domain.count('.') < domain.count('.'):
  166.             pass
  167.         elif domain.count('.') < MAX_SUBDOMAIN_CHECK:
  168.             new_domain = '.'.join(domain.split('.')[1:])
  169.             wx.CallAfter(fetch_favicon, new_domain, linked_domains + [
  170.                 domain])
  171.             return None
  172.         else:
  173.             log.error('%r', resp)
  174.             cache_noicon(domain, linked_domains)
  175.         unset_fetching(linked_domains + [
  176.             domain])
  177.  
  178.     
  179.     def on_redirect(req):
  180.         if 'favicon' not in req.get_selector():
  181.             new_url = 'http://%s/%s' % (req.get_host(), 'favicon.ico')
  182.             old_req = req._orig_request
  183.             checked_urls = getattr(old_req, '_favicons_checked_urls', set())
  184.             if new_url in checked_urls:
  185.                 return None
  186.             
  187.             checked_urls.add(new_url)
  188.             req = req.copy(url = new_url)
  189.             req._favicons_checked_urls = old_req._favicons_checked_urls = checked_urls
  190.             req._orig_request = old_req
  191.         
  192.         return req
  193.  
  194.     fetch_lock.__enter__()
  195.     
  196.     try:
  197.         if domain in currently_fetching:
  198.             log.info('already fetching %r', url)
  199.             return None
  200.         else:
  201.             log.info('getting %r', url)
  202.             currently_fetching.add(domain)
  203.     finally:
  204.         pass
  205.  
  206.     (None, None, fetch_lock, netcall)((lambda : asynchttp.httpopen(url, success = on_success, error = on_error, on_redirect = on_redirect)))
  207.  
  208. fetch_lock = RLock()
  209. currently_fetching = set()
  210.  
  211. def set_fetching(domain):
  212.     fetch_lock.__enter__()
  213.     
  214.     try:
  215.         currently_fetching.add(domain)
  216.     finally:
  217.         pass
  218.  
  219.  
  220.  
  221. def unset_fetching(domains):
  222.     global currently_fetching
  223.     fetch_lock.__enter__()
  224.     
  225.     try:
  226.         currently_fetching -= set(domains)
  227.     finally:
  228.         pass
  229.  
  230.  
  231.  
  232. def is_fetching(domain):
  233.     fetch_lock.__enter__()
  234.     
  235.     try:
  236.         return domain in currently_fetching
  237.     finally:
  238.         pass
  239.  
  240.  
  241.